require 'digest/sha1'
class User < ActiveRecord::Base
  
  #acts_as_audited
  
  cattr_accessor :current_user
  
  has_many :contacts, :class_name => "Contact", :foreign_key => "responsible_user_id", :conditions => ['contacts.deleted_at IS NULL']
  has_many :open_contacts, :class_name => "Contact", :foreign_key => "responsible_user_id", :conditions => ["(contacts.deleted_at IS NULL) AND ((contacts.closed_at IS NULL) OR ((contacts.reopen_at > contacts.closed_at) AND (contacts.reopen_at < '#{Time.now.to_s(:db)}')))"]
  has_many :groups, :class_name => "Group", :foreign_key => "responsible_person_id"
  has_many :live_contacts, :class_name => "Contact", :foreign_key => "responsible_user_id",
                           :conditions => ["((contacts.closed_at IS NULL) OR ((contacts.reopen_at > contacts.closed_at) AND (contacts.reopen_at < '#{Time.now.to_s(:db)}')))"]
  has_many :contacts_closed_last_week, :class_name => "Contact", :foreign_key => "responsible_user_id", :conditions => ["closed_at BETWEEN ? AND ?", Time.now - 9.days, Time.now]
  has_one :person, :class_name => "Person", :foreign_key => "user_id"
  has_many :small_groups_i_lead, :through => :person
  has_many :departments, :through => :person
  #has_many :ministries, :through => :person
  has_many :teams, :through => :person
  has_many :follow_ups, :class_name => "FollowUp", :through => :contacts
  has_many :recent_follow_ups, :through => :contacts, :source => :follow_ups,
                                                      :conditions => ["follow_ups.created_at > '#{(Time.now - 45.days).to_s(:db)}'"],
                                                      :order => ['follow_ups.created_at ASC']

                                          
  # ---------------------------------------
  # The following code has been generated by role_requirement.
  # You may wish to modify it to suit your need
  has_and_belongs_to_many :roles
  has_and_belongs_to_many :ministries
  
  attr_protected :roles

  def do_this
    VolunteerMailer.deliver_sent
  end
  
  # has_role? simply needs to return true or false whether a user has a role or not.  
  # It may be a good idea to have "admin" roles return true always
  def has_role?(role_in_question)
    @_list ||= self.roles.collect(&:name)
    return true if @_list.include?("admin")
    (@_list.include?(role_in_question.to_s) )
  end
  
  def authorized_for_ministry?(ministry_in_question)
    @_mlist ||= self.ministries.collect(&:ministry_id)
   # return true if @_list.include?("admin")
    @_mlist.include?(ministry_in_question)
  end
  
  def responsible_for_contact?(contact_in_question)
    @contact = Contact.find(contact_in_question)
    self.id == @contact.responsible_user_id ? true : false
  end
  
  def authorized_for_contact?(contact_in_question)
    ministry_id = Contact.find(contact_in_question).responsible_ministry_id
    @_clist ||= self.contacts.collect(&:id)
    #return true if self.roles.include?("admin")
    @_clist.include?(contact_in_question) #or self.authorized_for_ministry?(ministry_id.to_s)
  end
  
  def authorized_for_follow_up?(follow_up_in_question)
    return true if self.has_role?("admin")
    follow_up_in_question.created_by == self.login ? true : false
  end
  
  def authorized_for_note?(note)
    return true if (self.has_role?("admin") or self.has_role?("confidential"))
    note.created_by == self.login ? true : false
  end
  
  # ---------------------------------------
    
  
  
  # Virtual attribute for the unencrypted password
  attr_accessor :password

  validates_presence_of     :login, :email
  validates_presence_of     :password,                   :if => :password_required?
  validates_presence_of     :password_confirmation,      :if => :password_required?
  validates_length_of       :password, :within => 4..40, :if => :password_required?
  validates_confirmation_of :password,                   :if => :password_required?
  validates_length_of       :login,    :within => 3..40
  validates_length_of       :email,    :within => 3..100
  validates_uniqueness_of   :login, :email, :case_sensitive => false
  validates_uniqueness_of   :crypted_password
  before_save :encrypt_password

  # Authenticates a user by their login name and unencrypted password.  Returns the user or nil.
  def self.authenticate(login, password)
    u = find_by_login(login) # need to get the salt
    u && u.authenticated?(password) ? u : nil
  end

  # Encrypts some data with the salt.
  def self.encrypt(password, salt)
    Digest::SHA1.hexdigest("--#{salt}--#{password}--")
  end

  # Encrypts the password with the user salt
  def encrypt(password)
    self.class.encrypt(password, salt)
  end

  def authenticated?(password)
    crypted_password == encrypt(password)
  end

  def remember_token?
    remember_token_expires_at && Time.now.utc < remember_token_expires_at 
  end

  # These create and unset the fields required for remembering users between browser closes
  def remember_me
    self.remember_token_expires_at = 2.weeks.from_now.utc
    self.remember_token            = encrypt("#{email}--#{remember_token_expires_at}")
    save(false)
  end

  def forget_me
    self.remember_token_expires_at = nil
    self.remember_token            = nil
    save(false)
  end
  
  def full_name
    self.first_name + ' ' + self.last_name
  end
  
  def last_first_name
    self.last_name + ', ' + self.first_name
  end
  
  def average_open_contact_age
      ages = self.open_contacts.collect {|c| c.age_in_days.floor}
      ages.sum/ages.length
  end
  
  def in_progress_contacts
      self.open_contacts.reject {|c| c.follow_ups.empty?}
  end
  
  def in_progress_status
    if self.in_progress_contacts.length == 1
        "#{self.in_progress_contacts.length} of your open contacts is in progress."
    else
        "#{self.in_progress_contacts.length} of your open contacts are in progress."
    end
  end
  
  def follow_ups_last_week
    FollowUp.find(:all, :conditions => ['follow_ups.created_by = ? AND follow_ups.created_at BETWEEN ? AND ?', self.login, Time.now - 9.days, Time.now])
  end
  
  def forgot_password
       @forgotten_password = true
       self.make_password_reset_code
   end

     def reset_password
       # First update the password_reset_code before setting the 
       # reset_password flag to avoid duplicate email notifications.
       update_attributes(:password_reset_code => '')
       @reset_password = true
     end

     def recently_reset_password?
       @reset_password
     end

     def recently_forgot_password?
       @forgotten_password
     end
     
     def readable_scope
         case self.group_scope
         when "archived_on IS NULL"
             "Live"
         when "archived_on IS NOT NULL"
             "Archived"
         when "1 = 1"
             "All"
         when nil
             "I Don't Know"
         else
             "Else"
         end
      end

     protected

     def make_password_reset_code
       self.password_reset_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
     end
     
     

  protected
    # before filter 
    def encrypt_password
      return if password.blank?
      self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
      self.crypted_password = encrypt(password)
    end
    
    def password_required?
      crypted_password.blank? || !password.blank?
    end
end
